import numpy as np

class Player(object):
    '''I spent hours fiddling with various different bot techniques, including
    tit-for-tat. It turns out to do quite poorly when people are playing randomly.
    This one consistently survived and on the rare occasion even won.
    Generally nice player...can surive if other nice players around. Get's
    killed if villain ratio is high. This class also implements basic logic that
    my other player classes derived from (so there is some left over stuff).'''
    def __init__(self, good_rep_thresh=0.5, good_low=0.5, good_high=0.999, bad_low=0.5, initial_rep=0.8):
        self.name = "MyPlayer001[%f]" % (bad_low)
        self.round_number = 0

        self.initial_rep = 0.8
        self.parasite_hunter_round = 4

        self.good_rep_thresh = good_rep_thresh
        self.good_low = good_low
        self.good_high = good_high

        self.bad_low = bad_low

        np.random.seed(5)

    def hunt_choices(
                    self,
                    round_number,
                    current_food,
                    current_reputation,
                    m,
                    player_reputations,
                    ):
        '''Required function defined in the rules'''
        if round_number == 1:
            self.first_round(round_number, current_food, current_reputation, m,
                             player_reputations)

        self.round_number = round_number
        self.current_food = current_food
        self.current_reputation = current_reputation
        self.total_players = len(player_reputations) + 1

        # In the rare case that there are only two players (yourself included).
        # This is the end state -- so switch to slack (most optimal choice).
        if self.total_players == 2:
            return ['s']

        # First round you want to set yourself as highly reputable, but not
        # reputable enough to have 1. The logic behind this is that if you
        # come across a 1, people will think you are a hunt always and may
        # target your for parastism.
        if round_number == 1:
            # Set an initial number of players to hunt with
            hunt_players = int(len(player_reputations) * self.initial_rep)
            # Slack with the remaining
            slack_players = len(player_reputations) - hunt_players
            actions = ['h'] * hunt_players
            actions += ['s'] * slack_players
            return actions

        self.total_player_rep = np.sum(player_reputations + [current_reputation])
        self.average_rep = self.total_player_rep / self.total_players
        self.relative_player_reputations = np.array(player_reputations) / self.total_player_rep

        return self.logic(round_number, current_food, current_reputation, m, player_reputations)


    def first_round(self,
                    round_number,
                    current_food,
                    current_reputation,
                    m,
                    player_reputations,
                    ):
        '''For initializing variables you may need, but cannot do in logic. 
        Used by other Player derivatives.'''
        pass


    def logic(self,
              round_number,
              current_food,
              current_reputation,
              m,
              player_reputations,
              ):
        '''Non-optimal logic'''
        max_rep = -1
        # find the highest rep which is not 1
        hunter_present = False
        for player_rep in player_reputations:
            if player_rep == 1:
                hunter_present = True
                continue
            if player_rep > max_rep:
                max_rep = player_rep

        actions = []
        for player_rep, relative_rep in zip(player_reputations, self.relative_player_reputations):
            # This is clearly a hunt always bot. I feel bad about this, but
            # parastism on it might keep us alive longer. Sorry, bro.
            if round_number > self.parasite_hunter_round and player_rep == 1:
                actions.append('s')
                continue

            # Always work with the highest rep person(s), even if they are
            # kind of villains this is the only chance to weed out slackers.
            # It is a big risk, but it is the only way.
            if max_rep > 0.001 and player_rep == max_rep:
                actions.append('h')
                continue

            if current_reputation > self.average_rep:
                # I am considered a nice guy?
                if self.good_low <= player_rep <= self.good_high:
                    actions.append('h')
                else:
                    actions.append('s')
            else:
                # I am likely considered a bad guy at this point and there is a
                # low probability people will work with me. Too many villains in
                # this game.
                if player_rep <= self.bad_low:
                    actions.append('s')
                else:
                    r = np.random.random()
                    if r > player_rep:
                        actions.append('s')
                    else:
                        actions.append('h')

        return actions
    
    def hunt_outcomes(self, food_earnings):
        '''Required function defined in the rules'''
        pass
        

    def round_end(self, award, m, number_hunters):
        '''Required function defined in the rules'''
        pass